package com.dj.common.web.interceptor;

import java.sql.Connection;
import java.util.Properties;

import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.DefaultReflectorFactory;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.ReflectorFactory;
import org.apache.ibatis.reflection.factory.DefaultObjectFactory;
import org.apache.ibatis.reflection.factory.ObjectFactory;
import org.apache.ibatis.reflection.wrapper.DefaultObjectWrapperFactory;
import org.apache.ibatis.reflection.wrapper.ObjectWrapperFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.dj.common.web.service.tablesplit.ContextHelper;
import com.dj.common.web.service.tablesplit.Strategy;
import com.dj.common.web.service.tablesplit.TableSplit;
import com.dj.common.web.vo.PageAndSortVo;

@Intercepts({ @Signature(type = StatementHandler.class, method = "prepare", args = { Connection.class }) })
public class TableSplitInterceptor implements Interceptor {
	private final Logger logger = LoggerFactory.getLogger(this.getClass());

	private static final ObjectFactory DEFAULT_OBJECT_FACTORY = new DefaultObjectFactory();

	private static final ObjectWrapperFactory DEFAULT_OBJECT_WRAPPER_FACTORY = new DefaultObjectWrapperFactory();
	private static final ReflectorFactory  DEFAULT_REFIECTOR_FACTORY = new DefaultReflectorFactory();

	@Override
	public Object intercept(Invocation invocation) throws Throwable {
		StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
		MetaObject metaStatementHandler = MetaObject.forObject(statementHandler, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY, DEFAULT_REFIECTOR_FACTORY);
				
		Object parameterObject = metaStatementHandler.getValue("delegate.boundSql.parameterObject");
		doSplitTable(metaStatementHandler, parameterObject);
		// 传递给下一个拦截器处理  
		return invocation.proceed();

	}

	@Override
	public Object plugin(Object target) {
		// 当目标类是StatementHandler类型时，才包装目标类，否者直接返回目标本身,减少目标被代理的次数  
		if (target instanceof StatementHandler) {
			return Plugin.wrap(target, this);
		} else {
			return target;
		}
	}

	@Override
	public void setProperties(Properties properties) {

	}

	private void doSplitTable(MetaObject metaStatementHandler, Object parameterObject) throws ClassNotFoundException{
		
		String originalSql = (String) metaStatementHandler.getValue("delegate.boundSql.sql");
		if (StringUtils.isNotEmpty(originalSql)) {
			TableSplit tableSplit = null;
			if(StringUtils.equals(parameterObject.getClass().getSimpleName(), "PageAndSortVo")){
				@SuppressWarnings("rawtypes")
				PageAndSortVo pasv = (PageAndSortVo)parameterObject;
				tableSplit = pasv.getVo().getClass().getAnnotation(TableSplit.class);
			}else{
				tableSplit = parameterObject.getClass().getAnnotation(TableSplit.class);
			}

			// 根据配置自动生成分表SQL  
			if (tableSplit != null && tableSplit.split()) {
				Strategy strategy = ContextHelper.getStrategyManager().getStrategy(tableSplit.strategy());//获取分表策略来处理分表  
				if (strategy != null) {
					logger.info("[分表前的SQL]：" + originalSql);
					String convertedSql = originalSql.replaceAll(tableSplit.value(),
							strategy.convert(tableSplit.value(), tableSplit.strategy()));
					metaStatementHandler.setValue("delegate.boundSql.sql", convertedSql);
					logger.info("[分表后的SQL]：" + convertedSql);
				}
			}
		}
	}
}